
from django import template
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.forms import ValidationError
from django.http import Http404
from django.http import HttpResponse
from django.shortcuts import redirect
from django.shortcuts import render_to_response
from django.utils import simplejson
from sgx.validators import *
from transsys import *
from trsysmodis import *
from ts.config import *
from ts.utils import *
from ts.validators import *
from ts.views import *
from ts.views import _clean_expression_value
#import pdb; pdb.set_trace();
# Create your views here.

def sgxHome(request):
    #print request.session['ts_programs']
    request.session['sgx_program'] = None
    if request.session.get('sgx_programs', False):
        sgx_programs = request.session['sgx_programs']
    else:
        sgx_programs = []
        request.session['sgx_programs'] = sgx_programs
    request.session.modified = True
    return render_to_response('simgenex/index.html',
                              {},
                              context_instance=template.RequestContext(request))

def addSgx(request):
    """Add new SimGenex program via WEB interface"""
    if(request.method == "GET"):
        request.session["sgx_program"] = None
        request.session.modified = True
        return render_to_response('simgenex/addSgx.html',
                                  {'ts_programs':request.session['sgx_programs']},
                                  context_instance=template.RequestContext(request))
    elif(request.method == "POST"):
        try:
            sgx_name = _clean_sgx_name(request.session['sgx_programs'], request.REQUEST["name"])
            sgx_desc = str(request.REQUEST["desc"])
            tps_name = request.REQUEST.getlist("target_tp")

            target_tp = []
            for tp_name in tps_name:
                tp = _get_transsys_program_by_name(request, tp_name)
                if tp != None:
                    target_tp.append(tp)
            sgx = SimGenex([], [], [], [])

            sgx_program = {"name":sgx_name, "sgx":sgx, "desc":sgx_desc, "target_tp":target_tp}
            
            #ts_program = {'tp':TranssysProgram(tp_name) , 'desc':ts_desc}
            #print sgx_program
            if request.session.get('sgx_programs', False):
                request.session['sgx_programs'].append(sgx_program)
            else:
                request.session['sgx_programs'] = [sgx_program, ]
            request.session.modified = True
            return redirect(sgx_name + "/view")
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/addSgx.html',
                                      context_instance=template.RequestContext(request))

def uploadSgx(request):
    """Add new simgenex program from uploading file"""
    if(request.method == "GET"):
        request.session["sgx_program"] = None
        request.session.modified = True
        return render_to_response('simgenex/uploadSgx.html',
                                  context_instance=template.RequestContext(request))
    elif(request.method == "POST"):
        try:
            sgx_file = request.FILES["sgx_file"]
            sgx_parser = SimGenexObjectiveFunctionParser(sgx_file)
            sgx = sgx_parser.parse_simgenex()

            sgx_name = _clean_sgx_name(request.session['sgx_programs'], request.REQUEST["name"])
            sgx_desc = str(request.REQUEST["desc"])
            tps_name = request.REQUEST.getlist("target_tp")
            target_tp = []
            for tp_name in tps_name:
                tp = _get_transsys_program_by_name(request, tp_name)
                if tp != None:
                    target_tp.append(tp)

            sgx_program = {"name":sgx_name, "sgx":sgx, "desc":sgx_desc, "target_tp":target_tp}

            #ts_program = {'tp':TranssysProgram(tp_name) , 'desc':ts_desc}
            #print sgx_program
            if request.session.get('sgx_programs', False):
                request.session['sgx_programs'].append(sgx_program)
            else:
                request.session['sgx_programs'] = [sgx_program, ]
            request.session.modified = True
            return redirect(sgx_name + "/view")
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/uploadSgx.html',
                                      context_instance=template.RequestContext(request))


def delSgx(request, sgx_name):
    """Delete the simgenex program which has given name"""
    sgx_program = _check_sgx_name(request, sgx_name)
    
    sgx_programs = request.session['sgx_programs']
    
    cur_sgx_program = request.session['sgx_program']

    if sgx_program != cur_sgx_program:
        sgx_programs.remove(sgx_program)
        msg = "transsys program is removed successfully!"
        result = {"status":"success", "msg":msg}
    else:
        msg = "Unable to remove transsys program due to it is currently activated!"
        result = {"status":"failed", "msg":msg}
    request.session.modified = True
    return HttpResponse(simplejson.dumps(result), mimetype='application/javascript')

def viewSgx(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    #Update current transsys program in session
    #sgx_program["sgx"].simexpression_defs=[]
    request.session['sgx_program'] = sgx_program
    request.session.modified = True
    #print sgx_program["sgx"].simexpression_defs[0].invocation_instruction_list
    return render_to_response('simgenex/viewSgx.html',
                              context_instance=template.RequestContext(request))

def addTargetTp(request, sgx_name):
    """Add target transsys programs"""
    sgx_program = _check_sgx_name(request, sgx_name)
    if(request.method == "GET"):
        return render_to_response('simgenex/addTargetTp.html',
                                  context_instance=template.RequestContext(request))
    elif(request.method == "POST"):
        try:
            tps_name = request.REQUEST.getlist("target_tp")
            target_tp = sgx_program["target_tp"]
            for tp_name in tps_name:
                tp = _get_transsys_program_by_name(request, tp_name)
                if tp != None and (tp not in target_tp):
                    target_tp.append(tp)

            sgx_program["target_tp"]=target_tp
            request.session.modified = True
            return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/addTargetTp.html',
                                      context_instance=template.RequestContext(request))

def addProcedure(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    #Use traditional HTML form
    if(request.method == "GET"):
        return render_to_response('simgenex/addProcedure.html',
                                  context_instance=template.RequestContext(request))
    elif (request.method == "POST"):
        try:
            pname = _clean_procedure_name(sgx_program["sgx"], request.REQUEST["name"])
            i_type_list = request.REQUEST.getlist("itype")
            print i_type_list
            i_factor_list = request.REQUEST.getlist("ifactor")
            print i_factor_list
            i_expr_list = request.REQUEST.getlist("iexpr")
            print i_expr_list
            i_timestep_list = request.REQUEST.getlist("itimestep")
            print i_timestep_list
            i_gene_list = request.REQUEST.getlist("igene")
            print i_gene_list
            gene_list = request.REQUEST.getlist("gene")
            print gene_list
            factor_list = request.REQUEST.getlist("factor")
            print factor_list
            invocation_list = request.REQUEST.getlist("procedure")
            
            new_procedure = Procedure(pname, [])
            #new_procedure.instruction_list
            for i in range(len(i_type_list)):
                itype = str(i_type_list[i])
                if itype == "treatment":
                    ifactor = str(i_factor_list[i].split(":")[1])
                    iexpr = _clean_expression_value(i_expr_list[i])
                    instruction = TreatmentInstruction(ifactor, iexpr)
                elif itype == "runtimesteps":
                    itimestep = int(i_timestep_list[i])
                    instruction = RuntimestepsInstruction(itimestep)
                elif itype == "knockout":
                    igene = str(i_gene_list[i].split(":")[1])
                    instruction = KnockoutInstruction(igene)
                elif itype == "overexpress":
                    ifactor = str(i_factor_list[i].split(":")[1])
                    iexpr = _clean_expression_value(i_expr_list[i])
                    instruction = OverexpressionInstruction(ifactor, iexpr)
                elif itype == "setproduct":
                    gene = str(gene_list[i].split(":")[1])
                    factor = str(factor_list[i].split(":")[1])
                    instruction = SetproductInstruction(gene, factor)
                elif itype == "invocation":
                    pro_name = str(invocation_list[i])
                    procedure = _get_procedure_by_name(request, sgx_name, pro_name)
                    instruction = InvocationInstruction(procedure)

                new_procedure.instruction_list.append(instruction)
            
            #Set instruction to prodedure
            sgx_program["sgx"].procedure_defs.append(new_procedure)
            #print sgx_program["sgx"].procedure_defs
            request.session.modified = True
            return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/addProcedure.html',
                                      context_instance=template.RequestContext(request))

def editProcedure(request, sgx_name, pro_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    procedure = _get_procedure_by_name(request, sgx_name, pro_name)
    
    if(request.method == "GET"):
        inst_list = []
        for instruction in procedure.instruction_list:
            inst = {}
            pos = procedure.instruction_list.index(instruction) + 1
            if(pos % 2 == 1):
                css = "odd"
            else:
                css = "even"
            if isinstance(instruction, TreatmentInstruction):
                inst = {'id':'ins' + str(pos),
                    'del_id': 'del_ins' + str(pos),
                    'css':css,
                    "type":"treatment",
                    "factor":instruction.factor_name,
                    "expression_level":instruction.factor_concentration}
            elif isinstance(instruction, RuntimestepsInstruction):
                inst = {'id':'ins' + str(pos),
                    'del_id': 'del_ins' + str(pos),
                    'css':css,
                    "type":"runtimesteps",
                    "timestep":instruction.time_steps}
            elif isinstance(instruction, KnockoutInstruction):
                inst = {'id':'ins' + str(pos),
                    'del_id': 'del_ins' + str(pos),
                    'css':css,
                    "type":"knockout",
                    "gene":instruction.gene_name}
            elif isinstance(instruction, OverexpressionInstruction):
                inst = {'id':'ins' + str(pos),
                    'del_id': 'del_ins' + str(pos),
                    'css':css,
                    "type":"overexpress",
                    "factor":instruction.factor_name,
                    "constitute_value":instruction.constitute_value}
            elif isinstance(instruction, SetproductInstruction):
                inst = {'id':'ins' + str(pos),
                    'del_id': 'del_ins' + str(pos),
                    'css':css,
                    "type":"setproduct",
                    "gene":instruction.gene_name,
                    "factor":instruction.factor_name}
            elif isinstance(instruction, InvocationInstruction):
                inst = {'id':'ins' + str(pos),
                    'del_id': 'del_ins' + str(pos),
                    'css':css,
                    "type":"invocation",
                    "procedure":instruction.procedure}
            inst_list.append(inst)
        #print inst_list
        return render_to_response('simgenex/editProcedure.html',
                                  {'procedure':procedure,
                                  'inst_list':inst_list},
                                  context_instance=template.RequestContext(request))
    elif (request.method == "POST"):
        try:
            pname = str(request.REQUEST["name"])
            if pname != procedure.procedure_name:
                pname = _clean_procedure_name(sgx_program["sgx"], pname)
            i_type_list = request.REQUEST.getlist("itype")
            print i_type_list
            i_factor_list = request.REQUEST.getlist("ifactor")
            print i_factor_list
            i_expr_list = request.REQUEST.getlist("iexpr")
            print i_expr_list
            i_timestep_list = request.REQUEST.getlist("itimestep")
            print i_timestep_list
            i_gene_list = request.REQUEST.getlist("igene")
            print i_gene_list
            gene_list = request.REQUEST.getlist("gene")
            print gene_list
            factor_list = request.REQUEST.getlist("factor")
            print factor_list
            invocation_list = request.REQUEST.getlist("procedure")
            print invocation_list
            #new_procedure.instruction_list
            procedure.procedure_name = pname
            instruction_list = []
            for i in range(len(i_type_list)):
                itype = str(i_type_list[i])
                if itype == "treatment":
                    ifactor = str(i_factor_list[i].split(":")[1])
                    iexpr = _clean_expression_value(i_expr_list[i])
                    instruction = TreatmentInstruction(ifactor, iexpr)

                elif itype == "runtimesteps":
                    itimestep = int(i_timestep_list[i])
                    instruction = RuntimestepsInstruction(itimestep)
                elif itype == "knockout":
                    igene = str(i_gene_list[i].split(":")[1])
                    instruction = KnockoutInstruction(igene)
                elif itype == "overexpress":
                    ifactor = str(i_factor_list[i].split(":")[1])
                    iexpr = _clean_expression_value(i_expr_list[i])
                    instruction = OverexpressionInstruction(ifactor, iexpr)
                elif itype == "setproduct":
                    gene = str(gene_list[i].split(":")[1])
                    factor = str(factor_list[i].split(":")[1])
                    instruction = SetproductInstruction(gene, factor)
                elif itype == "invocation":
                    p_name = str(invocation_list[i])
                    pro = _get_procedure_by_name(request, sgx_name, p_name)
                    instruction = InvocationInstruction(pro)
                instruction_list.append(instruction)

            #Set instruction to prodedure
            procedure.set_instruction_list(instruction_list)
            #print sgx_program["sgx"].procedure_defs
            request.session.modified = True
            return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/addProcedure.html',
                                      context_instance=template.RequestContext(request))

def delProcedure(request, sgx_name, pro_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    procedure = _get_procedure_by_name(request, sgx_name, pro_name)
    if request.is_ajax():
        sgx_program["sgx"].procedure_defs.remove(procedure)
        request.session.modified = True
        msg = "The procedure is deleted successfully!"
        result = {"status":"success", "msg":msg}
        return HttpResponse(simplejson.dumps(result), mimetype='application/javascript')
    else:
        sgx_program["sgx"].procedure_defs.remove(procedure)
        request.session.modified = True
        return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))


def addSimexpression(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    #Use traditional HTML form
    if(request.method == "GET"):
        return render_to_response('simgenex/addSimexpression.html',
                                  context_instance=template.RequestContext(request))
    elif (request.method == "POST"):
        try:
            sname = _clean_procedure_name(sgx_program["sgx"], request.REQUEST["name"])
            i_type_list = request.REQUEST.getlist("itype")
            print i_type_list
            i_procedures_list = request.REQUEST.getlist("procedures")
            print i_procedures_list
            i_procedure_list = request.REQUEST.getlist("procedure")
            print i_procedure_list
            instruction_list = []
            for i in range(len(i_type_list)):
                itype = str(i_type_list[i])
                if itype == "foreach":
                    procedures = i_procedures_list[i].split(",")
                    invocation_instruction_list = []
                    for pro_name in procedures:
                        pro_name = pro_name.strip()
                        p_object = _get_procedure_by_name(request, sgx_name, pro_name)
                        invocation_instruction_list.append(InvocationInstruction(p_object))
                    instruction = ForeachInstruction(invocation_instruction_list)
                elif itype == "invocation":
                    p_object = _get_procedure_by_name(request, sgx_name, str(i_procedure_list[i]))
                    instruction = InvocationInstruction(p_object)
                instruction_list.append(instruction)
            new_simexpression = SimExpression(sname, instruction_list)

            #Set instruction to simexpression_defs
            sgx_program["sgx"].simexpression_defs.append(new_simexpression)
            #print sgx_program["sgx"].simexpression_defs[0]
            request.session.modified = True
            return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/addSimexpression.html',
                                      context_instance=template.RequestContext(request))
def editSimexpression(request, sgx_name, simex_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    simexpression = _get_simexpression_by_name(request, sgx_name, simex_name)
    #Use traditional HTML form
    if(request.method == "GET"):
        inst_list = []
        for instruction in simexpression.instruction_list:
            inst = {}
            pos = simexpression.instruction_list.index(instruction) + 1
            if(pos % 2 == 1):
                css = "odd"
            else:
                css = "even"
            if isinstance(instruction, InvocationInstruction):
                inst = {'id':'ins' + str(pos),
                    'del_id': 'del_ins' + str(pos),
                    'css':css,
                    "type":"invocation",
                    "procedure":instruction.get_procedure_name()}
            elif isinstance(instruction, ForeachInstruction):
                invocation_list = instruction.invocation_instruction_list
                #import pdb; pdb.set_trace();
                pros_str = ""
                
                for invocation in invocation_list:
                    pros_str = pros_str + invocation.get_procedure_name() + ", "

                inst = {'id':'ins' + str(pos),
                    'del_id': 'del_ins' + str(pos),
                    'css':css,
                    "type":"foreach",
                    "procedures": pros_str}
            inst_list.append(inst)
        #print inst_list
        return render_to_response('simgenex/editSimexpression.html',
                                  {'simexpression':simexpression,
                                  'inst_list':inst_list},
                                  context_instance=template.RequestContext(request))
    elif (request.method == "POST"):
        try:
            sname = _clean_procedure_name(sgx_program["sgx"], request.REQUEST["name"])
            i_type_list = request.REQUEST.getlist("itype")
            print i_type_list
            i_procedures_list = request.REQUEST.getlist("procedures")
            print i_procedures_list
            i_procedure_list = request.REQUEST.getlist("procedure")
            print i_procedure_list
            #instruction_list = []
            instruction_list = []
            for i in range(len(i_type_list)):
                itype = str(i_type_list[i])
                if itype == "foreach":
                    procedures = i_procedures_list[i].split(",")
                    invocation_instruction_list = []
                    for pro_name in procedures:
                        pro_name = pro_name.strip()
                        if pro_name != "":
                            p_object = _get_procedure_by_name(request, sgx_name, pro_name)
                            invocation_instruction_list.append(InvocationInstruction(p_object))
                    instruction = ForeachInstruction(invocation_instruction_list)
                elif itype == "invocation":
                    p_object = _get_procedure_by_name(request, sgx_name, str(i_procedure_list[i]))
                    instruction = InvocationInstruction(p_object)
                instruction_list.append(instruction)
            simexpression.set_instruction_list(instruction_list)
            request.session.modified = True
            return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/addSimexpression.html',
                                      context_instance=template.RequestContext(request))
def delSimexpression(request, sgx_name, simex_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    simexpression = _get_simexpression_by_name(request, sgx_name, simex_name)
    if request.is_ajax():
        sgx_program["sgx"].simexpression_defs.remove(simexpression)
        request.session.modified = True
        msg = "The simexpression is deleted successfully!"
        result = {"status":"success", "msg":msg}
        return HttpResponse(simplejson.dumps(result), mimetype='application/javascript')
    else:
        sgx_program["sgx"].simexpression_defs.remove(simexpression)
        request.session.modified = True
        return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))

def addMeasurementMatrix(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    if request.method == "GET":
        return render_to_response('simgenex/addMeasurementMatrix.html',
                                  context_instance=template.RequestContext(request))
    elif request.method == "POST":
        #Measurement process
        transformation_type = request.REQUEST["transformation"]
        try:
            offset_value = request.REQUEST["offset"]
            offset_value = float(offset_value)
            offset = Offset(offset_value)
        except KeyError, e:
            offset_value = OFFSET
            offset = Offset(offset_value)
        except:
            offset = None
        if transformation_type == "linear":
            transformation = TransformationExprOffset(TransformationExprMvar(ALTERNATIVE_CONDITION_IDENTIFIER))
        elif transformation_type == "log":
            linear = TransformationExprOffset(TransformationExprMvar(ALTERNATIVE_CONDITION_IDENTIFIER))
            transformation = TransformationExprLog2(linear)
        elif transformation_type == "log-ratio":
            linear = TransformationExprOffset(TransformationExprMvar(ALTERNATIVE_CONDITION_IDENTIFIER))
            a_log = TransformationExprLog2(linear)
            r_log = TransformationExprLog2(TransformationExprOffset(TransformationExprMvar(REFERENCE_CONDITION_IDENTIFIRER)))
            transformation = TransformationExprMinus(a_log, r_log)
        process = MeasurementProcess(offset, transformation)
        #Measurement columns
        measurement_column_list = []
        for simex in sgx_program["sgx"].simexpression_defs:
            column_header_list = simex.get_simulated_column_header_list()
            for i in column_header_list:
                if transformation_type == "log-ratio":
                    reference_column = request.REQUEST["reference"]
                    mvar1 = MvarAssignment(ALTERNATIVE_CONDITION_IDENTIFIER, i)
                    mvar2 = MvarAssignment(REFERENCE_CONDITION_IDENTIFIRER, reference_column)
                    col = MeasurementColumn(i, [mvar1, mvar2])
                    measurement_column_list.append(col)
                else:
                    mvar = MvarAssignment(ALTERNATIVE_CONDITION_IDENTIFIER, i)
                    col = MeasurementColumn(i, [mvar])
                    measurement_column_list.append(col)
        #Gene mapping
        genemapping = GeneMapping()
        for tp in sgx_program["target_tp"]:
            for factor in tp.factor_list:
                try:
                    genemapping.add_mapping(factor.name, factor.name)
                except StandardError:
                    pass
        #Measurement Matrix
        sgx_program["sgx"].measurementmatrix_def = MeasurementMatrix(process, measurement_column_list, genemapping)
        request.session.modified = True
        return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))

def getMeasurementColumns(request, sgx_name, transformation, reference_column):
    #TODO: Complete me
    sgx_program = _check_sgx_name(request, sgx_name)
    if request.is_ajax():
        measurement_column_list = []
        for simex in sgx_program["sgx"].simexpression_defs:
            column_header_list = simex.get_simulated_column_header_list()
            for i in column_header_list:
                if transformation == "log-ratio":
                    mvar1 = MvarAssignment(ALTERNATIVE_CONDITION_IDENTIFIER, i)
                    mvar2 = MvarAssignment(REFERENCE_CONDITION_IDENTIFIRER, reference_column)
                    col = MeasurementColumn(i, [mvar1, mvar2])
                    measurement_column_list.append(col)
                else:
                    mvar = MvarAssignment(ALTERNATIVE_CONDITION_IDENTIFIER, i)
                    col = MeasurementColumn(i, [mvar])
                    measurement_column_list.append(col)
        #msg = "The simexpression is deleted successfully!"
        result = {"status":"success", "measurement_column_list":str(measurement_column_list),}
        return HttpResponse(simplejson.dumps(result), mimetype='application/javascript')

def discriminationSetting(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    if request.method == "GET":
        return render_to_response('simgenex/discriminationSetting.html',
                                  context_instance=template.RequestContext(request))
    elif request.method == "POST":
        factor_whitelist = request.REQUEST.getlist("factor")
        gene_whitelist = request.REQUEST.getlist("gene")
        whitelist = WhiteList(factor_whitelist, gene_whitelist)
        distance = request.REQUEST["distance"]
        if distance == "correlation":
            discrimination = DiscriminationSettings(distance_correl, whitelist)
        elif distance == "euclidean":
            discrimination = DiscriminationSettings(distance_euclidean, whitelist)
        elif distance == "sum_squares":
            discrimination = DiscriminationSettings(distance_sum_squares, whitelist)
        sgx_program["sgx"].discriminationsettings_def = discrimination
        request.session.modified = True
        return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))

def codeSimgenex(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    if request.method == "GET":
        return render_to_response('simgenex/codeSimgenex.html',
                                  {'simgenex_code':str(sgx_program["sgx"]), },
                                  context_instance=template.RequestContext(request))
    elif request.method == "POST":
        try:
            sgx_code = str(request.REQUEST["simgenex_code"])
            #TODO: Validate and update transsys program
            import StringIO
            tmp = StringIO.StringIO(sgx_code)
            sgx_parser = SimGenexObjectiveFunctionParser(tmp)
            sgx = sgx_parser.parse_simgenex()

            sgx_program["sgx"] = sgx

            request.session.modified = True
            return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/codeSimgenex.html',
                                      {'simgenex_code':sgx_code, },
                                      context_instance=template.RequestContext(request))
        except StandardError, e:
            messages.error(request, str(e))
            return render_to_response('simgenex/codeSimgenex.html',
                                      {'simgenex_code':sgx_code, },
                                      context_instance=template.RequestContext(request))
def run(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    if request.method == "GET":
        return render_to_response('simgenex/runSimulation.html',
                                  context_instance=template.RequestContext(request))
    elif request.method == "POST":
        tp_name = request.REQUEST["tp"]
        tp = _get_transsys_program_by_name(request, tp_name)
        try :
            check_recursion(sgx_program["sgx"])
            expression_set = sgx_program["sgx"].get_simulated_set(tp)
            #create response object
            response = HttpResponse(mimetype='text/plain')
            response['Content-Disposition'] = 'attachment; filename=' + tp_name + '.dat'
            expression_set.write_expression_data(response)
            #expression_set.write_pheno_data(response)
            return response
        except StandardError, e:
            messages.error(request, str(e))
            return render_to_response('simgenex/runSimulation.html',
                                  context_instance=template.RequestContext(request))

def uploadExpressionSet(request, sgx_name):
    """Add new simgenex program from uploading file"""
    sgx_program = _check_sgx_name(request, sgx_name)
    if(request.method == "GET"):
        return render_to_response('simgenex/uploadExpressionSet.html',
                                  context_instance=template.RequestContext(request))
    elif(request.method == "POST"):
        try:
            name = _clean_expression_set_name(sgx_program,request.REQUEST["name"])
            expression_file = request.FILES["expression_file"]
            expression_set = ExpressionSet()
            expression_set.read(expression_file)
            if not sgx_program.has_key("target_expression_data"):
                sgx_program["target_expression_data"] = {name:expression_set,}
            else:
                sgx_program["target_expression_data"][name]=expression_set
            
            request.session.modified = True
            return redirect(reverse('sgx.views.viewExpressionSet', args=[sgx_name, name]) + "?next="+request.path)
        except ValidationError, e:
            messages.error(request, e.messages[0])
            return render_to_response('simgenex/uploadExpressionSet.html',
                                  context_instance=template.RequestContext(request))
        except StandardError, e1:
            messages.error(request, str(e1))
            return render_to_response('simgenex/uploadExpressionSet.html',
                                  context_instance=template.RequestContext(request))

def viewExpressionSet(request, sgx_name, ex_name):
    print sgx_name
    sgx_program = _check_sgx_name(request, sgx_name)
    next = request.REQUEST["next"]
    if(sgx_program["target_expression_data"].has_key(ex_name)):
        expression_set = sgx_program["target_expression_data"][ex_name]
        row_list = []
        for row in expression_set.get_row_name_list():
            fc_list=[]
            profile = expression_set.get_profile(row)
            for col in expression_set.get_column_name_list():
                fc_list.append(profile[col])
            item = {"name":row, "fc_list":fc_list}
            row_list.append(item)
        return render_to_response('simgenex/viewExpressionSet.html',
                                  {"name":ex_name,
                                   "expression_set":expression_set,
                                   "row_list":row_list},
                                  context_instance=template.RequestContext(request))
    else:
        messages.error(request, "Expression set does not exist")
        return redirect(next)

def delExpressionSet(request, sgx_name, ex_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    if request.is_ajax():
        if(sgx_program["target_expression_data"].has_key(ex_name)):
            expression_set = sgx_program["target_expression_data"][ex_name]
            sgx_program["target_expression_data"].pop(ex_name)
            msg = "The expression dataset is deleted successfully!"
            result = {"status":"success", "msg":msg}
            request.session.modified = True
            return HttpResponse(simplejson.dumps(result), mimetype='application/javascript')
        else:
            messages.error(request, "Expression set does not exist")
            result = {"status":"failed", "msg":msg}
            return HttpResponse(simplejson.dumps(result), mimetype='application/javascript')
    else:
        sgx_program["sgx"].simexpression_defs.remove(simexpression)
        request.session.modified = True
        return redirect(reverse('sgx.views.viewSgx', args=[sgx_name]))

def delTargetTranssysProgram(request, sgx_name, tp_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    target_tp = sgx_program["target_tp"]
    #tp = _get_transsys_program_by_name(request, tp_name)
    print target_tp
    for tp in target_tp:
        if tp.name == tp_name:
            target_tp.remove(tp)
            msg = "The target transsys program is deleted successfully!"
            result = {"status":"success", "msg":msg}
    request.session.modified = True
    return HttpResponse(simplejson.dumps(result), mimetype='application/javascript')
def compareTranssysModel(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    if request.method == "GET":
        return render_to_response('simgenex/compareTranssysModel.html',
                                  context_instance=template.RequestContext(request))
    elif request.method == "POST":
        can1 = request.REQUEST["candidate1"]
        can2 = request.REQUEST["candidate2"]
        input = {"can1":can1, "can2":can2}
        candidate1 = _get_transsys_program_by_name(request, can1)
        candidate2 = _get_transsys_program_by_name(request, can2)
        try :
            check_recursion(sgx_program["sgx"])
            expression_set_1 = sgx_program["sgx"].get_simulated_set(candidate1)

            reference = SimGenexObjectiveFunction(sgx_program["sgx"], expression_set_1)
            result = reference(candidate2)
            return render_to_response('simgenex/compareTranssysModel.html',
                                    {"result":result,
                                     "input":input},
                                  context_instance=template.RequestContext(request))
        except StandardError, e:
            messages.error(request, str(e))
            return render_to_response('simgenex/compareTranssysModel.html',
                                  context_instance=template.RequestContext(request))

def examineTranssysModel(request, sgx_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    if request.method == "GET":
        return render_to_response('simgenex/examineTranssysModel.html',
                                  context_instance=template.RequestContext(request))
    elif request.method == "POST":
        candidate_names = request.REQUEST.getlist("candidates")
        target_data = request.REQUEST["target_data"]
        input = {"target_data":target_data}
        candidates = []
        for candidate_name in candidate_names:
            candidates.append(_get_transsys_program_by_name(request, candidate_name))
        target_expression_set = sgx_program["target_expression_data"][target_data]
        try :
            check_recursion(sgx_program["sgx"])
            reference = SimGenexObjectiveFunction(sgx_program["sgx"], target_expression_set)
            result = {}
            for candidate in candidates:
                result[candidate.name] = reference(candidate)
            
            return render_to_response('simgenex/examineTranssysModel.html',
                                    {"result":result,
                                     "input":input},
                                  context_instance=template.RequestContext(request))
        except StandardError, e:
            messages.error(request, str(e))
            return render_to_response('simgenex/examineTranssysModel.html',
                                  context_instance=template.RequestContext(request))
                                  
################################################
##methods for internal usage####################
################################################


def _clean_sgx_name(sgxs, sgx_name):
    """Verify that given sgx_name is not existed in the SimGenex program list"""
    name = str(sgx_name)
    validators = [RequiredValidator(), UniqueSimGenexProgramValidator(sgxs)]
    run_validators(name, validators)
    return name

def _clean_procedure_name(sgx, p_name):
    """Verify that given p_name is valid"""
    name = str(p_name)
    validators = [RequiredValidator(), UniqueProcedureValidator(sgx)]
    run_validators(name, validators)
    return name

def _clean_expression_set_name(sgx_program, name):
    """Verify the expression set name is unique"""
    name = str(name)
    if sgx_program.has_key("target_expression_data"):
        for e_name, dataset in sgx_program["target_expression_data"].items():
            if (e_name == name):
                raise ValidationError("Expression set name is already exist!")
    return name
def _check_sgx_name(request, sgx_name):
    #Convert name from url to basic string
    sgx_name = sgx_name.replace("-", " ")
    #Find the transsys program with given name
    found = False
    #print request.session['sgx_programs']
    for sgx in request.session['sgx_programs']:
        if sgx["name"] == sgx_name:
            sgx_program = sgx
            found = True
    if(not found):
        msg = "SimGenex program " + sgx_name + " does not exist!"
        print msg
        raise Http404
    return sgx_program

def _get_procedure_by_name(request, sgx_name, pro_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    found = None
    for procedure in sgx_program["sgx"].procedure_defs:
        if pro_name == procedure.procedure_name:
            found = procedure
    if found:
        return found
    else:
        #TODO: send exception to request
        msg = "Procedure  " + pro_name + " does not exist!"
        print msg
        raise Http404

def _get_simexpression_by_name(request, sgx_name, simex_name):
    sgx_program = _check_sgx_name(request, sgx_name)
    found = None
    for simexpression in sgx_program["sgx"].simexpression_defs:
        if simex_name == simexpression.simexpression_name:
            found = simexpression
    if found:
        return found
    else:
        msg = "Simexpression  " + simex_name + " does not exist!"
        print msg
        raise Http404

def _get_transsys_program_by_name(request, tp_name):
    ts_programs = request.session["ts_programs"]
    found = None
    for ts_program in ts_programs:
        if tp_name == ts_program["tp"].name:
             found = ts_program["tp"]
    return found

def check_recursion(sgx_program):
    for procedure in sgx_program.procedure_defs:
        pathway = [procedure]
        try:
            _check_recursion(pathway, procedure)
        except StandardError, e:
            raise e
    
def _check_recursion(pathway, procedure):
    for instruction in procedure.instruction_list:
        if not isinstance(instruction, InvocationInstruction):
            print "NON RECURSION: " + _pathway_to_string(pathway) + "-->>" + str(instruction)
        else:
            if instruction.procedure in pathway:
                #Identify the longest subpath from the beginning to this procedure or between 2 same procedure
                longest_subpath = _longest_path(pathway, instruction.procedure)
                #Get the most recent path to current procedure with the same length
                recent_path = pathway[len(pathway)-len(longest_subpath):]
                if longest_subpath == recent_path:
                    print "RECURSION: " + _pathway_to_string(pathway) + "-->>" +instruction.procedure.procedure_name
                    raise StandardError, 'There is a recursion in procedure definitions: %s' % (_pathway_to_string(pathway)+ instruction.procedure.procedure_name)
                else:
                    pathway.append(instruction.procedure)
                    _check_recursion(pathway, instruction.procedure)
            else:
                pathway.append(instruction.procedure)
                _check_recursion(pathway, instruction.procedure)

def _longest_path(pathway, node):
    #Identify the longest path from the beginning to this node or between 2 node refer to the same object
    if (pathway.count(node)>1):
        start = pathway.index(node)+1
        #print start
        end = pathway[start:].index(node)+start
        #print end
    else:
        start = 0
        end = pathway.index(node)
    return pathway[start:end]

def _pathway_to_string(pathway):
    path = ""
    for p in pathway:
        path += p.procedure_name + "->"
    return path

